package com.dmj.sqldsl.util;

import static org.junit.jupiter.api.Assertions.assertEquals;

import cn.hutool.core.bean.BeanUtil;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.experimental.UtilityClass;
import org.junit.jupiter.api.Assertions;

@UtilityClass
public class AssertUtils {

  @SafeVarargs
  public static <T, F> void assertBeanEquals(T expected, T actual,
      GetMethodLambda<T, F>... ignoreFields) {
    String[] ignoreFieldNameArray = getFieldNameArray(ignoreFields);
    Object expectedObject = BeanUtil.copyProperties(expected, expected.getClass(),
        ignoreFieldNameArray);
    Object actualObject = BeanUtil.copyProperties(actual, actual.getClass(), ignoreFieldNameArray);
    if (!Objects.equals(expectedObject, actualObject)) {
      Assertions.assertEquals(expected, actual);
    }
  }

  @SafeVarargs
  public static <T, F> void assertListEquals(List<T> expectedList, List<T> actualList,
      GetMethodLambda<T, F>... ignoreFields) {

    if (Objects.isNull(expectedList) && Objects.isNull(actualList)) {
      return;
    }

    if (Objects.isNull(expectedList) || Objects.isNull(actualList)) {
      assertEquals(expectedList, actualList);
    }
    String[] ignoreFieldNameArray = getFieldNameArray(ignoreFields);
    List<?> actual = actualList.stream()
        .map(x -> BeanUtil.copyProperties(x, x.getClass(), ignoreFieldNameArray))
        .collect(Collectors.toList());
    expectedList.stream()
        .map(x -> BeanUtil.copyProperties(x, x.getClass(), ignoreFieldNameArray))
        .forEach(x -> {
          boolean flag = actual.stream().anyMatch(y -> Objects.equals(x, y));
          if (!flag) {
            assertEquals(expectedList, actualList);
          }
        });
  }

  private static String[] getFieldNameArray(GetMethodLambda<?, ?>[] getMethodLambdas) {
    if (Objects.isNull(getMethodLambdas)) {
      return new String[0];
    }
    String[] fieldNames = new String[getMethodLambdas.length];
    for (int i = 0; i < getMethodLambdas.length; i++) {
      fieldNames[i] = getMethodLambdas[i].getFieldName();
    }
    return fieldNames;
  }
}
